package com.example.myDesignPatterns.创建者模式.单例模式;
/**
 * 饿汉式：类加载就会导致该单实例对象被创建
 * 懒汉式：类加载不会导致该单实例对象被创建，而是首次使用该对象时才会创建
 */
//（静态变量方式）饿汉
// 该方式在成员位置声明Singleton类型的静态变量，并创建Singleton类的对象instance。
// instance对象是随着类的加载而创建的。如果该对象足够大的话，而一直没有使用就会造成内存
// 的浪费。
public class Singleton {
    // 静态实例变量，确保只有一个实例存在。
    private static Singleton instance = new Singleton();

    // 私有构造方法，防止外部实例化对象。
    private Singleton() {
    }
    public static Singleton getInstance() {
        return instance;
    }
}

//静态代码块方式）饿汉
//该方式在成员位置声明Singleton类型的静态变量，而对象的创建是在静态代码块中，也是对着
//类的加载而创建。所以和饿汉式的方式1基本上一样，当然该方式也存在内存浪费问题。
class Singleton1 {
    private static Singleton1 instance;

    static {
        instance = new Singleton1();
    }

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        return instance;
    }
}


/**
 * （线程不安全） 懒汉
 * 从下面Singleton2我们可以看出该方式在成员位置声明Singleton类型的静态变量，
 * 并没有进行对象的赋值操作，那么什么时候赋值的呢？
 * 当调用getInstance()方法获取Singleton类的对象的时候才创建Singleton类的对象，
 * 这样就实现了懒加载的效果。
 * 但是，如果是多线程环境，会出现线程安全问题。
 */

class Singleton2 {
    private static Singleton2 instance;

    private Singleton2() {
    }

    public static Singleton2 getInstance(){
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
}


/**
 * （线程安全） 懒汉
 * Singleton3也实现了懒加载效果，同时又解决了线程安全问题。
 * 但是在getInstance()方法上添加了synchronized关键字，导致该方法的执行效果特别低。
 * 从Singleton3代码我们可以看出，
 * 其实就是在初始化instance的时候才会出现线程安全问题，一旦初始化完成就不存在了
 */
class Singleton3 {
    private static Singleton3 instance;

    private Singleton3() {
    }

    public static synchronized Singleton3 getInstance(){
        if(instance == null){
            instance = new Singleton3();
        }
        return instance;
    }
}


/**
 * （双重检查锁方式） 懒汉
 * 双重检查锁模式是一种非常好的单例实现模式，解决了单例、性能、线程安全问题，
 * Singleton4的双重检测锁模式看上去完美无缺，其实是存在问题，
 * 在多线程的情况下，可能会出现空指针问题，
 * 出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
 * 要解决双重检查锁模式带来空指针异常的问题，只需要使用 volatile 关键字,
 * volatile 关键字可以保证可见性和有序性
 */
class Singleton4 {
    private Singleton4(){}

    //添加 volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式，
    //能够保证在多线程的情况下线程安全也不会有性能问题。
    private static volatile Singleton4 instance;
    public static Singleton4 getInstance(){
        //第一次判断，如果instance不为null，不进入抢锁阶段，直接返回实例
        if(instance == null){
            synchronized (Singleton4.class){
                //抢到锁之后再次判断是否为null
                if(instance == null){
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}


/**
 *  （静态内部类方式） 懒汉
 *  静态内部类单例模式中实例由内部类创建，
 *  由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的,
 *  只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。
 *  静态属性由于被static 修饰，保证只被实例化一次，并且严格保证实例化顺序。
 *
 * 静态内部类单例模式是一种优秀的单例模式，是开源项目中比较常用的一种单例模式。
 * 在没有加任何锁的情况下，保证了多线程下的安全，并且没有任何性能影响和空间的浪费
 */
class Singleton5 {
    private Singleton5(){}
    /**
     * 第一次加载Singleton类时不会去初始化INSTANCE，
     * 只有第一次调用getInstance，虚拟机加载SingletonHolder并初始化INSTANCE，
     * 这样不仅能确保线程安全，也能保证 Singleton 类的唯一性。
     * @return
     */
    private static class SingletonHolder{
        private static final Singleton5 INSTANCE = new Singleton5();
    }
    public static final Singleton5 getInstance(){
        return SingletonHolder.INSTANCE;
    }
}


/**
 * （枚举方式）饿汉
 * 枚举单例模式是线程安全的，在多线程的情况下，JVM会保证enum类的初始化时只有一个线程。
 */
/*
public enum Singleton {
    INSTANCE;
}*/
